package com.medsoft.drpcp.server;

import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_MSG_BODY_OFFSET;
import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_MSG_ID_LEN;
import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_MSG_ID_OFFSET;
import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_SERVICE_ID_LEN;
import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_SERVICE_ID_OFFSET;
import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_CRC32_LEN;
import static com.medsoft.drpcp.meta.DrpcpHeadConstant.DRPCP_CRC32_OFFSET;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.medsoft.base.utils.CRCUtils;
import com.medsoft.base.utils.EncryptUtils;
import com.medsoft.base.utils.JsonUtils;
import com.medsoft.drpcp.Bootstrapper;
import com.medsoft.drpcp.DrpcpRouter;
import com.medsoft.drpcp.GlobalConfig;
import com.medsoft.drpcp.ServiceDefinition;
import com.medsoft.drpcp.ServiceDefinitionContainer;
import com.medsoft.drpcp.exception.DrpcpException;
import com.medsoft.drpcp.meta.DrpcpHead;
import com.medsoft.drpcp.meta.DrpcpHeadConstant;

public class RpcServiceDispatcher {
	static final Logger logger = LoggerFactory.getLogger(RpcServiceDispatcher.class);
	
	public static String execute(Object msg) {
		String serviceId = msg.toString().substring(DRPCP_SERVICE_ID_OFFSET,DRPCP_SERVICE_ID_LEN);
		String drpcpMsgId = msg.toString().substring(DRPCP_MSG_ID_OFFSET,DRPCP_MSG_ID_OFFSET + DRPCP_MSG_ID_LEN);
		String crc32 = msg.toString().substring(DRPCP_CRC32_OFFSET, DRPCP_CRC32_OFFSET + DRPCP_CRC32_LEN);
		String paramJsonStr = msg.toString().substring(DRPCP_MSG_BODY_OFFSET);
		String tmpParamJsonStr = "";
		ServiceDefinition serviceDefinition = ServiceDefinitionContainer.getService(serviceId);
		String retJsonStr = "";
		
		if(Integer.parseInt(crc32) != CRCUtils.getCRC32Value(paramJsonStr)) {
			try {
				retJsonStr = getErrorDrpcpHead(serviceDefinition,
						GlobalConfig.encrypt,
						DrpcpHeadConstant.ERROR_NO_CRC32_CHECK_FAIL,
						DrpcpHeadConstant.ERROR_INFO_CRC32_CHECK_FAIL,
						drpcpMsgId);
				return serviceId + drpcpMsgId + CRCUtils.getCRC32Value(retJsonStr) + retJsonStr;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		try {
			if(GlobalConfig.encrypt) 
				tmpParamJsonStr = EncryptUtils.aesDecrypt(paramJsonStr);
			else 
				tmpParamJsonStr = paramJsonStr;
		} catch (Exception e1) {
			e1.printStackTrace();
			try {
				retJsonStr = getErrorDrpcpHead(serviceDefinition,
						GlobalConfig.encrypt,
						DrpcpHeadConstant.ERROR_NO_DECRYPT_FAIL,
						DrpcpHeadConstant.ERROR_INFO_DECRYPT_FAIL,
						drpcpMsgId);
				return serviceId + drpcpMsgId + CRCUtils.getCRC32Value(retJsonStr) + retJsonStr;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if (serviceDefinition.getNodeName().equals("drpcp.localService")) { //调用本地服务
			Object bean = Bootstrapper.getBean(serviceDefinition.getClz());
			if(bean == null) {
				try {
					retJsonStr = getErrorDrpcpHead(serviceDefinition,
							GlobalConfig.encrypt,
							DrpcpHeadConstant.ERROR_NO_NOT_FOUND,
							DrpcpHeadConstant.ERROR_INFO_NOT_FOUND,
							drpcpMsgId);
					return serviceId + drpcpMsgId + CRCUtils.getCRC32Value(retJsonStr) + retJsonStr;
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				try {
					Object retObj = serviceDefinition.getMethod().invoke(bean, JsonUtils.deserialize(tmpParamJsonStr, serviceDefinition.getParamType()));
					((DrpcpHead) retObj).setDrpcpMsgId(drpcpMsgId);
					((DrpcpHead) retObj).setDrpcpErrorNo(DrpcpHeadConstant.ERROR_NO_SUCCESS);
					((DrpcpHead) retObj).setDrpcpErrorInfo(DrpcpHeadConstant.ERROR_INFO_SUCCESS);
					retJsonStr = (GlobalConfig.encrypt ? EncryptUtils.aesEncrypt(JsonUtils.toJson(retObj)) : JsonUtils.toJson(retObj));
					return serviceId + drpcpMsgId + CRCUtils.getCRC32Value(retJsonStr) + retJsonStr;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} else if (serviceDefinition.getNodeName().equals("")) {
			throw new DrpcpException("service " + serviceDefinition.getServiceId() + "'s route is incorrect, cannot forward!");
		} else {
			// 正常转发调用drpcp服务,充当AR的角色
			try {
				retJsonStr = DrpcpRouter.call(serviceId, drpcpMsgId,crc32, paramJsonStr,serviceDefinition);
				return serviceId + drpcpMsgId + CRCUtils.getCRC32Value(retJsonStr) + retJsonStr;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		throw new DrpcpException("drpcp library bug, unreachable path!");
	}
	
	public static String getErrorDrpcpHead(ServiceDefinition sd,boolean encrypt,int errorNo,String errorInfo,String drpcpMsgId) throws Exception {
		Object ret = null;
		if(sd == null) {
			ret = new DrpcpHead();
		} else {
			try {
				ret = sd.getRetType().newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				e.printStackTrace();
				ret = new DrpcpHead();
			}
		}
		((DrpcpHead) ret).setDrpcpMsgId(drpcpMsgId);
		((DrpcpHead) ret).setDrpcpErrorNo(errorNo);
		((DrpcpHead) ret).setDrpcpErrorInfo(errorInfo);
		return (encrypt ? EncryptUtils.aesEncrypt(JsonUtils.toJson(ret)) : JsonUtils.toJson(ret));
	}
}
